package _case

import (
	"fmt"
	"io"
	"log"
	"os"
)

// defer关键字用来声明一个延迟调用函数
// 该函数可以是匿名函数也可以是具名函数
// defer延迟函数执行顺序为后进先出
func DeferCase1() {
	fmt.Println("开始执行")
	defer func() {
		fmt.Println("调用匿名函数defer")
	}()
	defer f2()
	fmt.Println("结束执行")
}

// 参数预计算
func DeferCaseCase2() {
	i := 1
	defer func(j int) { //因为i=1已经当作参数注册到了defer的匿名函数中
		fmt.Println("defer，传参j=1", j) // 所以这里打印 2
	}(i + 1)
	// 闭包函数，匿名函数内部可以访问外部函数
	defer func() {
		fmt.Println("defer", i) // i还没有注册到defer中，根据i最后的值进行打印
	}()
	// go里专门有一个存放defer的列表，将延迟调用的函数加入列表中（函数中传递的参数也会一同加入到这个列表中）
	i = 99
	fmt.Println(i)
}

// 返回值
// defer函数执行在return之后
func DeferCase3() {
	i, g := f3()
	fmt.Printf("i = : %d,g = : %d j = : %d", i, *g, j)
}

var j = 100

func f3() (int, *int) {
	defer func() {
		j = 200
	}()
	fmt.Println("f3的 j:", j)
	return j, &j
}

func f2() {
	fmt.Println("执行Defer2，调用匿名函数")
}

// 异常处理
func ExceptionCase() {
	defer func() {
		err := recover() //恢复当前协程，获得error信息
		if err != nil {
			fmt.Println("恢复协程，捕获异常 =======", err)
		}
	}()
	fmt.Println("开始执行异常处理函数ExceptionCase")
	panic("Painc抛出异常ExceptionCase")
	fmt.Println("异常处理函数ExceptionCase执行结束")

}

// 资源释放
func FileReadCase() {
	file, err := os.Open("README.md")
	if err != nil {
		log.Fatal(err) //会自动退出程序，所以不需要return
	}
	// 通过defer调用资源释放的方法
	defer func() {
		fmt.Println("释放文件资源")
		file.Close()
	}()
	buf := make([]byte, 1024)
	for {
		n, err := file.Read(buf)
		if err != nil && err != io.EOF { //io.EOF 是一个特殊的"错误"，表示已经到达文件或流的末尾
			log.Fatal("文件为打开失败", err)
		}
		if n == 0 {
			break
		}
		fmt.Println(buf[:n])
	}
}
